import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, 
                             QHBoxLayout, QLabel, QPushButton, QMessageBox, 
                             QScrollArea, QFrame)
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QFont
import random

class PianoKey(QPushButton):
    def __init__(self, note, is_black=False, parent=None):
        super().__init__(parent)
        self.note = note
        self.is_black = is_black
        
        # 设置键的尺寸
        if is_black:
            self.setFixedSize(23, 120)  # 黑键尺寸 (宽度较小，高度较短)
        else:
            self.setFixedSize(38, 200)  # 白键尺寸 (更宽更高)
        
        # 设置颜色
        self.normal_color = "#000000" if is_black else "#FFFFFF"
        self.pressed_color = "#333333" if is_black else "#DDDDDD"
        self.highlight_color = "#4CAF50"  # 正确时的高亮颜色
        self.wrong_color = "#FF5733"      # 错误时显示红色
        
        self.update_style()
        
        # 显示音符标签
        self.label = QLabel(note, self)
        self.label.setAlignment(Qt.AlignCenter)
        font = QFont("Arial", 8 if is_black else 10)
        font.setBold(True)
        self.label.setFont(font)
        self.label.setStyleSheet("color: white;" if is_black else "color: black;")
        
        if is_black:
            self.label.setGeometry(0, 80, 23, 30)
        else:
            self.label.setGeometry(0, 160, 38, 30)
            
        self.label.hide()
    
    def update_style(self):
        self.setStyleSheet(f"""
            QPushButton {{
                background-color: {self.normal_color};
                border: 1px solid #888888;
                border-radius: 0px;
            }}
            QPushButton:pressed {{
                background-color: {self.pressed_color};
            }}
        """)
    
    def highlight(self, correct=False):
        color = self.highlight_color if correct else self.wrong_color
        self.setStyleSheet(f"""
            QPushButton {{
                background-color: {color};
                border: 1px solid #000000;
                border-radius: 0px;
            }}
        """)

class PianoWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.white_keys = []
        self.black_keys = []
        self.setFixedHeight(220)
    
    def resizeEvent(self, event):
        # 定位黑键到白键上方正确位置
        for black_key in self.black_keys:
            # 每个黑键对应特定的白键位置
            index = black_key.white_key_index
            if 0 <= index < len(self.white_keys):
                white_key = self.white_keys[index]
                # 将黑键定位在白键的右上方
                black_key.move(white_key.pos().x() + white_key.width() - black_key.width()//2 - 1, 
                               white_key.pos().y())
        super().resizeEvent(event)

class PianoTrainer(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("钢琴键位学习助手")
        self.setGeometry(100, 100, 1000, 400)
        
        self.current_note = ""
        self.score = 0
        self.attempts = 0
        self.keys = {}  # 初始化keys字典
        
        self.initUI()
        self.generate_random_note()
    
    def initUI(self):
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        main_layout = QVBoxLayout()
        central_widget.setLayout(main_layout)
        
        # 信息显示区域
        info_layout = QHBoxLayout()
        self.note_label = QLabel("请点击对应的键位: ")
        self.note_label.setFont(QFont("Arial", 24, QFont.Bold))
        self.score_label = QLabel("得分: 0/0")
        self.score_label.setFont(QFont("Arial", 16))
        
        info_layout.addWidget(self.note_label)
        info_layout.addStretch()
        info_layout.addWidget(self.score_label)
        main_layout.addLayout(info_layout)

        # 钢琴键盘区域 (不带滚动条)
        self.piano_widget = PianoWidget()
        self.piano_layout = QHBoxLayout(self.piano_widget)
        self.piano_layout.setSpacing(0)
        self.piano_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.addWidget(self.piano_widget)

        # 创建钢琴键盘
        self.create_piano_keys()
        
        # 控制按钮
        control_layout = QHBoxLayout()
        new_note_btn = QPushButton("新音符")
        new_note_btn.clicked.connect(self.generate_random_note)
        show_keys_btn = QPushButton("显示所有键位")
        show_keys_btn.clicked.connect(self.toggle_key_labels)
        reset_btn = QPushButton("重置分数")
        reset_btn.clicked.connect(self.reset_score)
        
        control_layout.addWidget(new_note_btn)
        control_layout.addWidget(show_keys_btn)
        control_layout.addWidget(reset_btn)
        main_layout.addLayout(control_layout)
    
    def create_piano_keys(self):
        # 标准88键钢琴键盘布局 (A0到C8)
        # 白键顺序: A0,B0,C1,D1,E1,F1,G1,A1,B1,C2,...,C8
        # 黑键位于某些白键之间
        
        # 首先创建所有白键
        white_notes = []
        octaves = [0, 1, 2, 3, 4, 5, 6, 7, 8]
        # white_keys = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
        white_keys = ['C', 'D', 'E', 'F', 'G', 'A', 'B']

        for octave in octaves:
            for key in white_keys:
                # 跳过不存在的键位
                if octave == 0 and key not in ['A', 'B']:
                    continue
                if octave == 8 and key != 'C':
                    continue
                
                note = f"{key}{octave}"
                white_notes.append(note)
        
        # 创建白键
        for i, note in enumerate(white_notes):
            key = PianoKey(note, False, self.piano_widget)
            key.clicked.connect(self.key_clicked)
            self.piano_layout.addWidget(key)
            self.piano_widget.white_keys.append(key)
            self.keys[note] = key
        
        # 创建黑键并关联到对应的白键位置
        # 黑键位于特定白键之间:
        # A#0(不存在), C#1, D#1, F#1, G#1, A#1, C#2, ...
        black_notes = []
        black_positions = []  # 记录黑键对应的白键索引
        
        for octave in range(0, 8):
            # A#
            # if octave > 0:  # A#0不存在
            black_notes.append(f"A#{octave}")
            black_positions.append(0 + (octave)*7)  # A键的位置
            

            if octave < 7:
                # C#
                black_notes.append(f"C#{octave+1}")
                black_positions.append(2 + (octave)*7)  # C键的位置
                
                # D#
                black_notes.append(f"D#{octave+1}")
                black_positions.append(3 + (octave)*7)  # D键的位置
                
                # F#
                black_notes.append(f"F#{octave+1}")
                black_positions.append(5 + (octave)*7)  # F键的位置
                
                # G#
                black_notes.append(f"G#{octave+1}")
                black_positions.append(6 + (octave)*7)  # G键的位置
        
        # 过滤掉不存在的黑键(如C#8)
        valid_black_notes = []
        valid_positions = []
        for note, pos in zip(black_notes, black_positions):
            if pos < len(self.piano_widget.white_keys):
                valid_black_notes.append(note)
                valid_positions.append(pos)
        
        # 创建黑键
        for note, pos in zip(valid_black_notes, valid_positions):
            key = PianoKey(note, True, self.piano_widget)
            key.clicked.connect(self.key_clicked)
            key.white_key_index = pos  # 关联到对应的白键索引
            self.piano_widget.black_keys.append(key)
            self.keys[note] = key
        
        # 调整钢琴键盘总宽度
        total_width = len(self.piano_widget.white_keys) * 38
        self.piano_widget.setFixedWidth(total_width)
    
    def key_clicked(self):
        sender = self.sender()
        selected_note = sender.note
        
        if selected_note == self.current_note:
            self.score += 1
            sender.highlight(correct=True)
            QMessageBox.information(self, "正确", f"恭喜你！{self.current_note}是正确的！")
        else:
            # 高亮显示正确的键和错误的键
            if self.current_note in self.keys:
                self.keys[self.current_note].highlight(correct=True)
            sender.highlight(correct=False)
            
            QMessageBox.warning(self, "错误", 
                               f"不正确。你点击了 {selected_note}，但正确答案是 {self.current_note}。")
        
        self.attempts += 1
        self.update_score()
        self.generate_random_note()
    
    def generate_random_note(self):
        # 重置所有键的样式
        for key in self.keys.values():
            key.update_style()
            key.label.hide()
        
        # 生成随机音符
        available_notes = list(self.keys.keys())
        self.current_note = random.choice(available_notes)
        self.note_label.setText(f"请点击: {self.current_note}")
    
    def toggle_key_labels(self):
        # 切换所有键的音符标签显示/隐藏
        for key in self.keys.values():
            if key.label.isVisible():
                key.label.hide()
            else:
                key.label.show()
    
    def update_score(self):
        percentage = int(self.score/self.attempts*100) if self.attempts > 0 else 0
        self.score_label.setText(f"得分: {self.score}/{self.attempts} ({percentage}%)")
    
    def reset_score(self):
        self.score = 0
        self.attempts = 0
        self.update_score()
        self.generate_random_note()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    trainer = PianoTrainer()
    trainer.show()
    sys.exit(app.exec_())